<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
<title>Events</title>
<link rel="stylesheet" href="doc.css" type="text/css" />
</head>
<body>
<div class="document">
<div class="navigation navigation-header container">
<span class="previous">Previous: <a class="reference" href="sprites.html" title="Sprites">Sprites</a></span><span class="next">Next: <a class="reference" href="actions_transformations_and_effects.html" title="Actions, Transformations and Effects">Actions, Transformations ...</a></span><span class="breadcrumbs"><a class="reference" href="index.html" title="Programming Guide">Programming Guide</a> » <a class="reference" href="basic_concepts.html" title="Basic Concepts">Basic Concepts</a> » Events</span></div>
<h1 class="title">Events</h1>

<p>cocos2d uses <a class="reference" href="http://www.pyglet.org/doc/programming_guide/the_pyglet_event_framework.html">The pyglet Event Framework</a> to handle events.</p>
<div class="section" id="the-pyglet-event-framework-in-a-pinch">
<h1><a class="toc-backref" href="#id134">The pyglet event framework in a pinch</a></h1>
<blockquote>
<ul>
<li><p class="first">you have <strong>emitters</strong> (instances of pyglet.event.EventDispatcher)</p>
</li>
<li><p class="first">each emitter registers as much events as desired, each one identified by a
string (the event name)</p>
</li>
<li><p class="first">to act over events, you register <strong>listeners</strong> with the emitter.
Essentially, you provide the emitter with a (&lt;event name&gt;, callable) and the
emitter will call the callable when &lt;event name&gt; happens.
Any number of listeners can register for a (emitter, &lt;event name&gt;) pair.
A listener can register to any number of emitters.</p>
</li>
<li><p class="first">example registration <strong>emitter</strong> events:</p>
<pre class="py-doctest">
<span class="py-keyword">class</span> <span class="py-defname">Bunker</span>(pyglet.event.EventDispatcher):
<span class="py-more">    ...</span>
    <span class="py-keyword">def</span> <span class="py-defname">building_update</span>(self, dt):
<span class="py-more">        ...</span>
    <span class="py-keyword">if</span> self.elapsed_time&gt;self.building_time:
        self.dispatch_event(<span class="py-string">'on_building_complete'</span>, self)

<span class="py-keyword">def</span> <span class="py-defname">take_damage</span>(self, damage):
    self.dispatch_event(<span class="py-string">'on_building_under_attack'</span>, self)
    self.life -= damage
    <span class="py-keyword">if</span> self.life&lt;0:
        self.dispatch_event(<span class="py-string">'on_building_destroyed'</span>, self)

<span class="py-comment"># following lines register the events that Bunker instances can emit</span>
Bunker.register_event_type(<span class="py-string">'on_building_complete'</span>)
Bunker.register_event_type(<span class="py-string">'on_building_under_attack'</span>)
Bunker.register_event_type(<span class="py-string">'on_building_destroyed'</span>)</pre>
<p>Note that an event can carry zero, one or more arguments; here we send the
instance emitting the event.</p>
</li>
<li><p class="first">example registration <strong>listeners</strong>:</p>
<pre class="py-doctest">
<span class="py-keyword">class</span> <span class="py-defname">Commander</span>(object):
    <span class="py-keyword">def</span> <span class="py-defname">__init__</span>(self, ...):
        self.buildings = []
<span class="py-more">        ...</span>

    <span class="py-keyword">def</span> <span class="py-defname">invest_resources</span>(self):
<span class="py-more">        ...</span>
        bunker = Bunker(...)
        <span class="py-comment"># register to receive all events from object bunker</span>
        bunker.push_handlers(self)
        self.buildings.append(bunker)
<span class="py-more">        ...</span>

    <span class="py-comment"># handlers for the events</span>

    <span class="py-keyword">def</span> <span class="py-defname">on_building_complete</span>(self, building):
<span class="py-more">        ...</span>

    <span class="py-keyword">def</span> <span class="py-defname">on_building_under_attack</span>(self, building):
<span class="py-more">        ...</span>

    <span class="py-keyword">def</span> <span class="py-defname">on_building_destroyed</span>(self, building):
<span class="py-more">        ...</span></pre>
<p>Note that the handlers accepts the parameters that the event carries.
The listener registration here works as:</p>
<blockquote>
<ul class="simple">
<li>we pass a class instance to push_handlers</li>
<li>pyglet will look at methods in this class instance whose name match
&lt;event name&gt; for any &lt;event name&gt; which the emitter registered, and
then register ( &lt;event name&gt;, obj.event_name ) for each match.</li>
</ul>
</blockquote>
<p>With this style of listener registration you should be careful when
registering for two emitters: if both emitters can generate 'on_cuack'
events and you register:</p>
<pre class="py-doctest">
emitter1.push_handlers(obj)
emitter2.push_handlers(obj)</pre>
<p>then obj.on_cuack will be called by both emitters.</p>
<p>Another listener registration style is pushing explicit handlers:</p>
<pre class="py-doctest">
bunker.push_handlers(
    self.on_building_complete,
    self.on_building_under_attack,
    self.on_building_destroyed
    )</pre>
</li>
<li><p class="first">When you want a listener to stop receiving events from an emitter, you de-register the listener:</p>
<pre class="py-doctest">
emitter.remove_handlers(...) <span class="py-comment"># params as in push_handlers</span></pre>
</li>
<li><p class="first">Event propagation : The event is propagated to all handlers from the top of the emitter stack until one returns EVENT_HANDLED.</p>
</li>
</ul>
</blockquote>
</div>
<div class="section" id="cocos-and-events">
<h1><a class="toc-backref" href="#id135">Cocos and events</a></h1>
<p>Besides using events to get user input ('on_key_press', 'on_mouse_move',...) or window status change ( 'on_activate', ... )
, you can use events to decouple the model from the view in your app. The game Tetrico, to be found in samples/tetrico is an example of this usage.</p>
<p>Cocos in general will <strong>not</strong> automatically handle listeners registration/de-registration, except for one special case: the emitter is director.window and the listener is a layer or scene
Thus, for the general case, you must handle the push_handlers - remove_handlers thing by yourself.
When your listener lives in a CocosNode, a good scheme is pushing handlers in the on_enter method and remove handlers in the on_exit method. This way, you are sure your handlers will not be called when the node is not in the active scene.
Also, for custom events, it is a good practice to not use event names that director.window uses: that prevents unexpected double calls to the handler(s).</p>
<p>For the special case that emitter is director.window and the listeners are layers or scenes, cocos can handle the registration / de-registration:</p>
<blockquote>
<ul>
<li><p class="first">When a scene becomes active it would walk the scene tree to allow layers autoregistering for director.window events
It would not attempt to register itself as a listener except if the scene.enable_handlers is called.
The walk begins in the scene, and passes only to layer class childs.</p>
</li>
<li><p class="first">When prompted from the above walk, a layer whose class member is_event_handler has value True will register itself as a director.window listener
The registration will be on the form:</p>
<pre class="py-doctest">
director.window.push_handler(layer)</pre>
<p>so any method whose name matchs a &lt;event name&gt; will be registered as a listener.</p>
</li>
<li><p class="first">When the scene becomes inactive ( by director.pop by example ), the matching walk calling:</p>
<pre class="py-doctest">
director.window.remove_handlers(layer)</pre>
<p>will be issued.</p>
</li>
</ul>
</blockquote>
<p>Events generated by cocos itself:</p>
<blockquote>
<ul class="simple">
<li>( director, 'on_push' )</li>
<li>( director, 'on_pop' )</li>
<li>( director, 'on_resize' )</li>
<li>( director, 'on_cocos_resize')</li>
</ul>
</blockquote>
<p>Cocos registers a default key listener that provides handy functionality, see <a class="reference sectionlink" href="default_handlers.html">Default Handlers</a></p>
</div>
<div class="navigation navigation-footer container">
<span class="previous">Previous: <a class="reference" href="sprites.html" title="Sprites">Sprites</a></span><span class="next">Next: <a class="reference" href="actions_transformations_and_effects.html" title="Actions, Transformations and Effects">Actions, Transformations ...</a></span><span class="breadcrumbs"><a class="reference" href="index.html" title="Programming Guide">Programming Guide</a> » <a class="reference" href="basic_concepts.html" title="Basic Concepts">Basic Concepts</a> » Events</span></div>
</div>
</body>
</html>
